//////////////////////////////////////////////////////////////////
// MattiseOS Kernel
// Date: 2008
// Author: Matthew Iselin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//////////////////////////////////////////////////////////////////

#ifndef DEVMAN_H
#define DEVMAN_H

// Defines
#define DEVREQ_OPEN		1
#define DEVREQ_READ		2
#define DEVREQ_WRITE	3
#define DEVREQ_SEEK		4
#define DEVREQ_CLOSE	5
#define DEVREQ_IOCTL	6
#define DEVREQ_STAT		7
#define DEVREQ_DUP		8
#define DEVREQ_MAXREQ	(DEVREQ_DUP)
#define DEVREQ_INVALID	0

// seeking stuff
#define SEEK_SET		0
#define SEEK_CUR		1
#define SEEK_END		2

// device manager errors
#define E_DMAN_NOERR	0
#define E_DMAN_NOROOM	1
#define E_DMAN_OUTOFMEM	2
#define E_DMAN_INVALARG	3
#define E_DMAN_FAILED	4

// Includes
#include <sys/stat.h>

// Types

// a file descriptor
struct fd {
	int avail;				// 0 if used

	int internaldesc;		// an internal descriptor given by the device open
							// call - -1 if no open call was made

	int devid;				// the device id that this descriptor relates to
							// this allows the device manager to decide what
							// calls to make when we re-enter kernel space

	int pid;				// the process for which this file descriptor works
};

// an I/O request
struct ioreq {
	struct ioreq* prev;		// the previous io request in the list

	int devid;				// the device id this request works with

	int req;				// what type of request (see values above)

	int pid;				// process that the request comes from

	int fdnum;				// file descriptor number

	int reqres;				// the result of the request

	size_t bcount;			// number of blocks to work with

	size_t bytecount;		// number of bytes to read

	int32_t iarg1;			// integer arguments (for things like seek and open and close)
	int32_t iarg2;
	int32_t iarg3;
	int32_t iarg4;

	char* kbuff;			// buffer for the kernel to place data into
							// this means we can do all I/O in kernel space
							// and not worry about a cross-segment data copy
							// should be page allocated, not kernel heap allocated
	char* kbuff_phys;		// physical address of the above buffer, DO NOT USE
							// EVER, ACCESS WILL CAUSE PAGEFAULTS!

	struct ioreq* next;		// the next io request in the list
};

// Prototypes

// sets up the device manager
void SetupDevMan();

// installs a new device
void InstallDevice(	const char* prefix,
					uint32_t s_open,
					uint32_t s_read,
					uint32_t s_write,
					uint32_t s_seek,
					uint32_t s_ioctl,
					uint32_t s_stat,
					uint32_t s_close,
					int blocksize
					);

// handles I/O requests
void HandleIO();

// the open system call
int32_t sys_open( const char* path, int32_t flags );

// the dup system call
int32_t sys_dup( int32_t fd );

// the read system call
size_t sys_read( int32_t fd, const void* buff, size_t count );

// the write system call
size_t sys_write( int32_t fd, void* buff, size_t count );

// the seek system call
size_t sys_seek( int32_t fd, size_t off, int32_t set );

// the ioctl system call
int32_t sys_ioctl( int32_t fd, int32_t action, int32_t data );

// the stat system call
int32_t sys_stat( int32_t fd, struct stat* buf );

// the read system call
int32_t sys_close( int32_t fd );

#endif
